﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.Creation;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Controls;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKArchUtils.Utils;

namespace YJKColumnModify
{
	public class AlignOperator
	{
		public AlignOperator(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
		}

		public Result Operate(ref string message)
		{
			Curve curve = null;
			Result result = this.SelectWallSideline(ref curve, ref message);
			if (result != Autodesk.Revit.UI.Result.Succeeded)
			{
				return result;
			}
			if (curve.GetType() == typeof(Line))
			{
				Line line = curve as Line;
				List<FamilyInstance> list = this.SelectMoveColumns();
				if (list.Count < 1)
				{
					return Autodesk.Revit.UI.Result.Cancelled;
				}
				Element selElement = null;
				Curve curve2 = this.SelectColumnProfileLine(ref selElement);
				Line line2 = curve2 as Line;
				if (null == line2)
				{
					message = "无法得到柱子边线！";
					return Autodesk.Revit.UI.Result.Failed;
				}
				if (list.FindIndex((FamilyInstance value) => value.Id.IntegerValue == selElement.Id.IntegerValue) == -1)
				{
					message = "所选边与不在选择的柱子集合内！";
					return Autodesk.Revit.UI.Result.Failed;
				}
				if (!Geometry.IsParallel(line2.Direction, line.Direction, 0.001))
				{
					message = "所选柱子边与墙边不平行，无法进行对齐墙边操作！";
					return Autodesk.Revit.UI.Result.Failed;
				}
				XYZ hyendPoint = curve2.GetEndPoint(0);
				if (hyendPoint == null)
				{
					return Autodesk.Revit.UI.Result.Failed;
				}
				XYZ xyz = Geometry.CalculateFootPoint(line, hyendPoint);
				XYZ xyz2 = null;
				string strB = "";
				foreach (FamilyInstance familyInstance in list)
				{
					if (familyInstance.Id.IntegerValue == selElement.Id.IntegerValue)
					{
						LocationPoint locationPoint = familyInstance.Location as LocationPoint;
						xyz2 = locationPoint.Point;
						double rotation = locationPoint.Rotation;
						strB = familyInstance.Symbol.Family.Name + familyInstance.Symbol.Name;
						break;
					}
				}
				YJKLineEx.YJKGetBound(hyendPoint, hyendPoint + line.Direction);
				XYZ xyz3 = xyz - hyendPoint;
				Line line3 = YJKLineEx.YJKGetBound(xyz2, xyz2 + line.Direction);
				using (List<FamilyInstance>.Enumerator enumerator = list.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						FamilyInstance familyInstance2 = enumerator.Current;
						if ((familyInstance2.Symbol.Family.Name + familyInstance2.Symbol.Name).CompareTo(strB) == 0)
						{
							XYZ point = (familyInstance2.Location as LocationPoint).Point;
							XYZ xyz4 = Geometry.CalculateFootPoint(line3, point) - point + xyz3;
							XYZ xyz5 = new XYZ(xyz4.X, xyz4.Y, 0.0);
							ElementTransformUtils.MoveElement(this.m_Revit.Application.ActiveUIDocument.Document, familyInstance2.Id, xyz5);
						}
					}
					return Autodesk.Revit.UI.Result.Succeeded;
				}
			}
			if (curve.GetType() == typeof(Arc))
			{
				Arc arc = curve as Arc;
				XYZ xyz6 = null;
				FamilyInstance familyInstance3 = null;
				string message2 = "";
				while (this.SelectOneColumn(ref familyInstance3, ref xyz6, ref message2))
				{
					if (familyInstance3 == null)
					{
						YJKMessageBox.Show(message2);
					}
					else
					{
						XYZ xyz7 = Geometry.CalculateFootPoint(arc, xyz6) - xyz6;
						XYZ xyz8 = new XYZ(xyz7.X, xyz7.Y, 0.0);
						ElementTransformUtils.MoveElement(this.m_Revit.Application.ActiveUIDocument.Document, familyInstance3.Id, xyz8);
					}
				}
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result SelectWallSideline(ref Curve wallSideLine, ref string message)
		{
			Reference reference = null;
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			try
			{
				reference = selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)4, "请选择要对齐的墙边");
			}
			catch (Exception)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			if (reference == null)
			{
				message = "无法得到墙体边线！";
				return Autodesk.Revit.UI.Result.Failed;
			}
			Element element = this.m_Revit.Application.ActiveUIDocument.Document.GetElement(reference);
			Face face = element.GetGeometryObjectFromReference(reference) as Face;
			Wall wall = element as Wall;
			if (null == face || wall == null)
			{
				message = "无法得到墙体边线！";
				return Autodesk.Revit.UI.Result.Failed;
			}
			Curve curve = (wall.Location as LocationCurve).Curve;
			if (curve.GetType() == typeof(Line))
			{
				Line curve2 = curve as Line;
				XYZ origin = (face as PlanarFace).Origin;
				XYZ xyz = new XYZ(origin.X, origin.Y, 0.0);
				XYZ xyz2 = new XYZ(curve2.GetEndPoint(0).X, curve2.GetEndPoint(0).Y, 0.0);
				XYZ xyz3 = new XYZ(curve2.GetEndPoint(1).X, curve2.GetEndPoint(1).Y, 0.0);
				XYZ xyz4 = Geometry.CalculateFootPoint(YJKLineEx.YJKGetBound(xyz2, xyz3), xyz);
				XYZ xyz5 = xyz - xyz4;
				XYZ startPoint = xyz2 + xyz5;
				XYZ endPoint = xyz3 + xyz5;
				wallSideLine = YJKLineEx.YJKGetBound(startPoint, endPoint);
			}
			else
			{
				if (!(curve.GetType() == typeof(Arc)))
				{
					return Autodesk.Revit.UI.Result.Failed;
				}
				Arc arc = curve as Arc;
				double length = (face as CylindricalFace).get_Radius(0).GetLength();
				XYZ hyendPoint;
				XYZ hyendPoint2;
				if (arc.Normal.Z < 0.0)
				{
					hyendPoint = curve.GetEndPoint(1);
					hyendPoint2 = curve.GetEndPoint(0);
				}
				else
				{
					hyendPoint = curve.GetEndPoint(0);
					hyendPoint2 = curve.GetEndPoint(1);
				}
				XYZ center = arc.Center;
                //(hyendPoint - center).Normalize() * length;
                //(hyendPoint2 - center).Normalize() * length;
				XYZ center2 = new XYZ(center.X, center.Y, 0.0);
				double num = XYZ.BasisX.AngleOnPlaneTo(hyendPoint - center, XYZ.BasisZ);
				double num2 = XYZ.BasisX.AngleOnPlaneTo(hyendPoint2 - center, XYZ.BasisZ);
				if (num2 < num)
				{
					num -= Math.PI*2;
				}
				wallSideLine = this.m_Revit.Application.ActiveUIDocument.Document.CreatYJKArc(center2, length, num, num2, XYZ.BasisX, XYZ.BasisY);
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Curve SelectColumnProfileLine(ref Element selElement)
		{
			Reference reference = null;
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			try
			{
				reference = selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, new ColumnFilter(), "请选择要对齐的柱子边");
			}
			catch (Exception)
			{
				return null;
			}
            Autodesk.Revit.DB.Document document = this.m_Revit.Application.ActiveUIDocument.Document;
			selElement = document.GetElement(reference);
			double elevation = AssistFunc.GetCurrentViewLevel(document).Elevation;
			XYZ xyz = new XYZ(reference.GlobalPoint.X, reference.GlobalPoint.Y, elevation);
			Element element = document.GetElement(reference) as FamilyInstance;
			List<Line> list = new List<Line>();
			Application create = this.m_Revit.Application.Application.Create;
			new ReferenceArray();
			Options options = create.NewGeometryOptions();
			options.ComputeReferences = true;
			options.View = this.m_Revit.Application.ActiveUIDocument.ActiveView;
			List<GeometryObject> geometryObjectArray = RevitVersionFuncs.GetGeometryObjectArray(element.get_Geometry(options));
			int i = 0;
			while (i < geometryObjectArray.Count)
			{
				GeometryObject geometryObject = geometryObjectArray[i];
				if (geometryObject is GeometryInstance)
				{
					using (List<GeometryObject>.Enumerator enumerator = RevitVersionFuncs.GetGeometryObjectArray((geometryObject as GeometryInstance).GetInstanceGeometry()).GetEnumerator())
					{
						while (enumerator.MoveNext())
						{
							GeometryObject geometryObject2 = enumerator.Current;
							Solid solid = geometryObject2 as Solid;
							this.GetLineEdgesInSolid(solid, ref list);
						}
						goto IL_168;
					}
					goto IL_14C;
				}
				goto IL_14C;
				IL_168:
				i++;
				continue;
				IL_14C:
				if (geometryObject is Solid)
				{
					Solid solid2 = geometryObject as Solid;
					this.GetLineEdgesInSolid(solid2, ref list);
					goto IL_168;
				}
				goto IL_168;
			}
			double num = 100000.0;
			Line result = null;
			for (int j = 0; j < list.Count; j++)
			{
				double num2 = list.ElementAt(j).Distance(xyz);
				if (num2 < num)
				{
					num = num2;
					Line curve = list.ElementAt(j);
					XYZ hyendPoint = curve.GetEndPoint(0);
					XYZ hyendPoint2 = curve.GetEndPoint(1);
					result = YJKLineEx.YJKGetBound(new XYZ(hyendPoint.X, hyendPoint.Y, elevation), new XYZ(hyendPoint2.X, hyendPoint2.Y, elevation));
				}
			}
			return result;
		}

		private void GetLineEdgesInSolid(Solid solid, ref List<Line> arEdges)
		{
			if (null != solid)
			{
				EdgeArray edges = solid.Edges;
				for (int i = 0; i < edges.Size; i++)
				{
                    Edge edge = edges.get_Item(i);
					if (edge.Tessellate().Count == 2)
					{
						Line line = edge.AsCurve() as Line;
						if (line != null && object.Equals(line.GetEndPoint(0).Z, line.GetEndPoint(1).Z))
						{
							arEdges.Add(line);
						}
					}
				}
			}
		}

		private List<FamilyInstance> SelectMoveColumns()
		{
			List<FamilyInstance> list = new List<FamilyInstance>();
			IList<Element> list2 = null;
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			try
			{
				list2 = selection.PickElementsByRectangle("框选需要对齐的柱子：");
			}
			catch (Exception)
			{
				return list;
			}
			foreach (Element element in list2)
			{
				FamilyInstance familyInstance = element as FamilyInstance;
				if (familyInstance != null)
				{
					Category category = familyInstance.Category;
					if (-2001330 == category.Id.IntegerValue || -2000100 == category.Id.IntegerValue)
					{
						list.Add(familyInstance);
					}
				}
			}
			return list;
		}

		protected bool SelectOneColumn(ref FamilyInstance refInstance, ref XYZ refPoint, ref string errorMessage)
		{
			Reference reference = null;
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			try
			{
				reference = selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)2, "点取柱上需要对齐到墙的点：");
			}
			catch (Exception)
			{
				errorMessage = "请选择柱子上的点";
				refInstance = null;
				return false;
			}
			Element element = this.m_Revit.Application.ActiveUIDocument.Document.GetElement(reference);
			if (element.GetType() != typeof(FamilyInstance))
			{
				errorMessage = "请选择柱子上的点";
				refInstance = null;
				return true;
			}
			FamilyInstance familyInstance = element as FamilyInstance;
			Category category = familyInstance.Category;
			if (-2001330 != category.Id.IntegerValue && -2000100 != category.Id.IntegerValue)
			{
				errorMessage = "请选择柱子上的点";
				refInstance = null;
				return true;
			}
			refInstance = familyInstance;
			refPoint = reference.GlobalPoint;
			return true;
		}

		private ExternalCommandData m_Revit;
	}
}
